(***********************************************************************)
(*                                                                     *)
(*  Programowanie Funkcyjne                                            *)
(*  Wydział MiMUW                                                      *)
(*                                                                     *)
(*  Marcin Walas                                                       *)
(*  262460                                                             *)
(*                                                                     *)
(***********************************************************************)
(*

*)

(* external imports go here *)
open GMain;;
open GWindow;;
open GPack;;

open OImages;;
open Images;;

open Printf;;

(* internal imports go here *)
open Common;;


(* Zmienne globalne na potrzeby GUI *)

let board_width = 600;;
let board_height = 600;;

let field_width = 75;;
let field_height = 75;;

let piece_width = 55;;
let piece_height = 55;;

let backing = ref (GDraw.pixmap ~width:board_width ~height:board_height ())





let redraw_board window backing rgb width height =
  let pixmap = GDraw.pixmap ~width ~height ~window () in

  pixmap#set_foreground `WHITE;
  pixmap#rectangle ~x:0 ~y:0 ~width ~height ~filled:true ();

  let weight = 200 in
  for x=0 to board_width-1 do
    for y=0 to board_height-1 do
        let a = (rgb#get x y) in
        pixmap#set_foreground (`RGB ((a.r*weight), (a.g*weight), (a.b*weight)));
        pixmap#point ~x:x ~y:y
    done;
  done;
  backing := pixmap;
  true;;


(* Create a new backing pixmap of the appropriate size *)
let refresh window backing rgb ev =
    eprintf "GUI NOTICE: refresh main window called\n";
    flush stderr;

    let width = GdkEvent.Configure.width ev in
    let height = GdkEvent.Configure.height ev in
    redraw_board window backing rgb width height;;

(* Redraw the screen from the backing pixmap *)
let expose (drawing_area:GMisc.drawing_area) (backing:GDraw.pixmap ref) ev =
  let area = GdkEvent.Expose.area ev in
  let x = Gdk.Rectangle.x area in
  let y = Gdk.Rectangle.y area in
  let width = Gdk.Rectangle.width area in
  let height = Gdk.Rectangle.width area in
  let drawing =
    drawing_area#misc#realize ();
    new GDraw.drawable (drawing_area#misc#window)
  in
  drawing#put_pixmap ~x ~y ~xsrc:x ~ysrc:y ~width ~height !backing#pixmap;
  false;;


(* Draw a rectangle on the screen *)

let draw_brush (area:GMisc.drawing_area) (backing:GDraw.pixmap ref) x y =
  let x = x - 5 in
  let y = y - 5 in
  let width = 10 in
  let height = 10 in
  let update_rect = Gdk.Rectangle.create ~x ~y ~width ~height in
  !backing#set_foreground `BLACK;
  !backing#rectangle ~x ~y ~width ~height ~filled:true ();
  area#misc#draw (Some update_rect)


let button_pressed handlers area backing ev =
    if GdkEvent.Button.button ev = 1 then (
        let x = int_of_float (GdkEvent.Button.x ev) in
        let y = int_of_float (GdkEvent.Button.y ev) in
        eprintf "GUI NOTICE: mouse click catched at %d %d \n" x y;
        flush stderr;

        let x_pos = x/field_width in
        let y_pos = y/field_height in 
        handlers.click_handler x_pos y_pos
    );
    true;;


(* Creates a window with properties of the game *)
let options_window handlers = 
    eprintf "GUI NOTICE: options window creation \n";
    flush stderr;

    let window = GWindow.window ~width:500 ~height:250 () in
    let vbox = GPack.vbox ~packing:window#add () in
    
(*    let *)
    let game_choose_label = GBin.frame ~label:"Choose a game"  ~packing:vbox#pack () in
    let game_choose = GPack.hbox ~packing:game_choose_label#add () in
    let checkers_radio = GButton.radio_button  ~packing:game_choose#add ~label:"Checkers" ~active:true () in
    let breaktrough_radio = GButton.radio_button  ~group:checkers_radio#group ~packing:game_choose#add ~label:"Breaktrough" () in
    

    let ai_label = GBin.frame ~label:"AI properties"  ~packing:vbox#pack () in
    let ai_choose = GPack.vbox ~packing:ai_label#add () in
    let ai_type = GPack.hbox ~packing:ai_choose#add () in
    let alpha_beta_radio = GButton.radio_button  ~packing:ai_type#add ~label:"Alpha/Beta algorithm" () in

    let alphabeta_label = GBin.frame ~label:"Alpha Beta properties"  ~packing:vbox#pack () in
    let alphabeta_choose = GPack.hbox ~packing:alphabeta_label#add () in
    let alphabeta_ = GMisc.label ~text:"recurency depth: " ~packing:alphabeta_choose#add () in
    let level_2 = GButton.radio_button ~label:"2" ~packing:alphabeta_choose#add () in
    let level_3 = GButton.radio_button ~label:"3" ~group:level_2#group ~packing:alphabeta_choose#add ~active:true () in
    let level_4 = GButton.radio_button ~label:"4" ~group:level_2#group ~packing:alphabeta_choose#add () in
    let level_5 = GButton.radio_button ~label:"5" ~group:level_2#group ~packing:alphabeta_choose#add () in
    let level_6 = GButton.radio_button ~label:"6" ~group:level_2#group ~packing:alphabeta_choose#add () in


    let players_label = GBin.frame ~label:"Red player properties"  ~packing:vbox#pack () in
    let red_choose = GPack.hbox ~packing:players_label#add () in
        let red_human = GButton.radio_button ~label:"Human" ~packing:red_choose#add ~active:true () in
        let red_computer = GButton.radio_button ~label:"Computer" ~group:red_human#group ~packing:red_choose#add () in

    let players2_label = GBin.frame ~label:"White player properties"  ~packing:vbox#pack () in
    let white_choose = GPack.hbox ~packing:players2_label#add () in 
        let white_human = GButton.radio_button ~label:"Human" ~packing:white_choose#add () in
        let white_computer = GButton.radio_button ~label:"Computer" ~group:white_human#group ~packing:white_choose#add ~active:true () in
  
    let exit_hbox = GPack.hbox ~packing:vbox#add () in
    let apply_button = GButton.button ~label:"Apply" ~packing:exit_hbox#add () in
    let reset_button = GButton.button ~label:"Reset" ~packing:exit_hbox#add () in

    apply_button#connect#clicked ~callback:
        (
        fun () ->             
            let game_type = if checkers_radio#active then Checkers else Breaktrough in 
            let red_human = red_human#active in
            let white_human = white_human#active in
            let alpha_beta_depth = if level_2#active then 2 else 
                (if level_3#active then 3 else
                    (if level_4#active then 4 else
                        (if level_5#active then 5 else
                            (if level_6#active then 6 else
                                0
                            )
                        )
                    )
                ) in

            (handlers.set_options_handler game_type {is_human = red_human} {is_human = white_human} alpha_beta_depth ); 
            ()
        );
    reset_button#connect#clicked ~callback:(
        fun () -> 
            (level_2#set_active true);
            (checkers_radio#set_active true);
            ()
        );

    window;;

(* Creating main window *)
let window = GWindow.window ~width:850 ~height:700 ();;

let board_background = OImages.load "chessboard.jpg" [];;
let board_background_rgb = OImages.rgb24(board_background );;


(* Adding widgets to main window *)
let vbox = GPack.vbox ~packing:window#add ();;
let area = GMisc.drawing_area ~width:600 ~height:600 ~packing:vbox#add ();;


let event_loop handlers () =
    handlers.idle_handler ();
    true;;


let main handlers () =
    let x  = handlers.click_handler in

    (* Creating other windows *)
    let opt_wnd = options_window handlers in

    (* Connecting singals *)
    window#connect#destroy ~callback:GMain.Main.quit;

    (* Connecting signals for area backing in pixmap *)
    area#event#connect#expose ~callback: (expose area backing);

    (* Event signals *)
(*    area#event#connect#motion_notify ~callback:(motion_notify area backing); *)
    area#event#connect#button_press ~callback:(button_pressed handlers area backing);

    area#event#add [`EXPOSURE; `LEAVE_NOTIFY; `BUTTON_PRESS; `POINTER_MOTION; `POINTER_MOTION_HINT];

    (* Create toolbar *)
    let hbox = GPack.hbox ~packing:vbox#add () in 
    let new_button = GButton.button ~label:"New game" ~packing:hbox#add () in
    let options_button = GButton.button ~label:"Options" ~packing:hbox#add () in
    let quit_button = GButton.button ~label:"Quit" ~packing:hbox#add () in

    (* Connecting toolbar *)
    options_button#connect#clicked ~callback:opt_wnd#show;
    quit_button#connect#clicked ~callback:window#destroy;
    new_button#connect#clicked ~callback:handlers.new_game_handler;

    (* Shows window *)
    window#show ();

    (* Dodanie timeoutu *)
    GMain.Timeout.add 10000 (event_loop handlers);

    (* start main loop of GTK *)
    GMain.Main.main ();;


(* Wrapper używany przez inne elementy aplikacji *)

module GuiManager =
    struct
        (* to zmienia właśnie stan wyświetlania się obiektów na planszy *)
        let redraw_background () = 
            eprintf "GuiManager : redraw background called \n";
            flush stderr;
            redraw_board window backing board_background_rgb board_width board_height;
            area#misc#draw (Some (Gdk.Rectangle.create 0 0 board_width board_height));;


        (* to rysuje pojedyńczą bitmapę na planszy *)
        let draw_bitmap (x_pos:int) (y_pos:int)(rgb: OImages.rgb24) = 
(*
            eprintf "GuiManager : draw_bitmap  %d %d \n" x_pos y_pos;
            flush stderr;
*)

            let x_delta = (x_pos*field_width) + (field_width-piece_width)/2 in
            let y_delta = (y_pos*field_height) + (field_height-piece_height)/2 in
            let weight = 200 in
            for x=0 to piece_width-1 do
                for y=0 to piece_height-1 do
                    let a = (rgb#get x y) in
                    (!backing)#set_foreground (`RGB ((a.r*weight), (a.g*weight), (a.b*weight)));
                    (!backing)#point ~x:(x_delta+x) ~y:(y_delta+y)
                done;
            done;
            area#misc#draw (Some (Gdk.Rectangle.create x_delta y_delta piece_width piece_height));;
    end;;




